﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Win32;

namespace WorkingFileManager
{
    /// <summary>
    /// Contains static methods that can be used in the View of an application to handle messages from the 
    /// viewmodel related to opening and saving files and showing the various dialogs in that process.
    /// </summary>
    public class ViewMethods
    {
        /// <summary>
        /// This method can be called in the View of an application to respond to a request from the viewmodel to open
        /// a new file via an OpenFileDialog. It takes care of logic for things like saving the currently-loaded data (and opening
        /// a corresponding SaveFileDialog).
        /// 
        /// Generally this method will be the response to an MVVM message that wraps an OpenFileDialogMessageParameters object.
        /// </summary>
        /// <param name="exitParams"></param>
        /// <param name="parentWindow"></param>
        /// <param name="saveChangesMessageBoxText"></param>
        /// <param name="saveChangesCaption"></param>
        public static void HandleOpenFileMessage(OpenFileMessageParameters openParams, Window parentWindow)
        {
            if (openParams.saveFileInfo.promptSaveChanges)
            {
                switch (System.Windows.MessageBox.Show(openParams.saveFileInfo.saveChangesPopupText, openParams.saveFileInfo.saveChangesPopupTitle, MessageBoxButton.YesNoCancel))
                {
                    case MessageBoxResult.Cancel:
                        //entire open operation should cancel
                        return;
                    case MessageBoxResult.No:
                        //just proceed with open
                        break;
                    case MessageBoxResult.Yes:
                        //user wants to save changes first
                        ViewMethods.SaveToCurrentFileOrChoose(openParams.saveFileInfo, parentWindow);
                        //now that previous file has been saved, we can proceed with open below
                        break;
                    default:
                        throw new Exception();
                }
            }

            OpenFileDialog ofd = new OpenFileDialog();
            if (!string.IsNullOrEmpty(openParams.InitialDirectory))
            {
                ofd.InitialDirectory = openParams.InitialDirectory;
            }

            ofd.Filter = openParams.Filter;
            if ((bool)ofd.ShowDialog(parentWindow))
            {
                openParams.FileOpenCallback(ofd.FileName);
            }
        }

        public static void HandleNewFileMessage(NewFileMessageParameters newParams, Window parentWindow)
        {
            if (newParams.saveFileInfo.promptSaveChanges)
            {
                switch (System.Windows.MessageBox.Show(newParams.saveFileInfo.saveChangesPopupText, newParams.saveFileInfo.saveChangesPopupTitle, MessageBoxButton.YesNoCancel))
                {
                    case MessageBoxResult.Cancel:
                        //entire new operation should cancel
                        return;
                    case MessageBoxResult.No:
                        //just proceed with new
                        break;
                    case MessageBoxResult.Yes:
                        //user wants to save changes first
                        ViewMethods.SaveToCurrentFileOrChoose(newParams.saveFileInfo, parentWindow);
                        //now that previous file has been saved, we can proceed with creating new file below
                        break;
                    default:
                        throw new Exception();
                }
            }

            newParams.FileNewCallback();
        }

        public static void HandleOpenRecentFileMessage(OpenRecentFileMessageParameters orfParams, Window parentWindow)
        {
            if (orfParams.saveFileInfo.promptSaveChanges)
            {
                switch (System.Windows.MessageBox.Show(orfParams.saveFileInfo.saveChangesPopupText, orfParams.saveFileInfo.saveChangesPopupTitle, MessageBoxButton.YesNoCancel))
                {
                    case MessageBoxResult.Cancel:
                        //entire new operation should cancel
                        return;
                    case MessageBoxResult.No:
                        //just proceed with opening recent file
                        break;
                    case MessageBoxResult.Yes:
                        //user wants to save changes first
                        ViewMethods.SaveToCurrentFileOrChoose(orfParams.saveFileInfo, parentWindow);
                        //now that previous file has been saved, we can proceed with open below
                        break;
                    default:
                        throw new Exception();
                }
            }

            orfParams.FileOpenCallback();
        }

        public static void HandleSaveFileMessage(SaveAsMessageParameters saveParams, Window parentWindow)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            if (!string.IsNullOrEmpty(saveParams.InitialDirectory))
            {
                sfd.InitialDirectory = saveParams.InitialDirectory;
            }

            sfd.Filter = saveParams.Filter;
            if ((bool)sfd.ShowDialog(parentWindow))
            {
                saveParams.FileSaveCallBack(sfd.FileName);
            }
        }

        /// <summary>
        /// This property is used during handling of the exit message to make it clear that the application
        /// is really shutting down and there should be no more dialog boxes. This allows the DefaultFilecommandImplementations
        /// to prevent a second Exit dialog box to be shown in cases where the user exits by clicking the X in the window chrome.
        /// </summary>
        public static bool ShuttingDown { get; set; }

        public static void HandleExitMessage(ExitMessageParameters exitParams, Window parentWindow)
        {
            if (!exitParams.saveFileInfo.promptSaveChanges)
            {
                Application.Current.Shutdown();
            }
            else
            {
                switch (ShowSaveChangesMessageBox(exitParams.saveFileInfo))
                {
                    case MessageBoxResult.Cancel:
                        //user does not want to exit at all
                        return;
                    case MessageBoxResult.No:
                        //just proceed with exit
                        break;
                    case MessageBoxResult.Yes:
                        //user wants to save changes before exiting
                        if (!ViewMethods.SaveToCurrentFileOrChoose(exitParams.saveFileInfo, parentWindow))
                        {
                            //user canceled out of the save file dialog. we should abort the exit
                            return;
                        }
                        //now that previous file has been saved, we can proceed with open below
                        break;
                }

                ShuttingDown = true;
                Application.Current.Shutdown();
            }
        }

        /// <summary>
        /// Shows a message box asking if the user wants to save changes, using the text information (caption etc) specified
        /// in a SaveFileInfo. This box may be shown, for example, when a file is opened or when the program is exited.
        /// </summary>
        /// <param name="sfi"></param>
        /// <returns></returns>
        private static MessageBoxResult ShowSaveChangesMessageBox(SaveFileInfo sfi)
        {
            return (System.Windows.MessageBox.Show(sfi.saveChangesPopupText, sfi.saveChangesPopupTitle, MessageBoxButton.YesNoCancel));
        }

        /// <summary>
        /// There is more than one scenario where a user will need to save a file before doing something else,
        /// including when another file is opened or when the program is exited. In those cases by "save" we
        /// really mean "save to the current file if there is one" and "gather a current file if there isn't one."
        /// This method encapsulates those rules.
        /// </summary>
        /// <param name="sfi"></param>
        /// <param name="parentWindow"/>
        /// <returns>False if the user clicked cancel in the save file dialog, so
        /// the operation that caused the dialog to come up in the first place should be canceled by the caller.
        /// For example, the user created a new file, made some changes, then exited. It asked if they wanted
        /// to save, they said yes, and then they clicked cancel. So we don't save but we also have to tell
        /// the caller that they should not proceed with the exit either.</returns>
        private static bool SaveToCurrentFileOrChoose(SaveFileInfo sfi, Window parentWindow)
        {
            if (string.IsNullOrEmpty(sfi.currentWorkingFile))
            {
                //there is no current working file. show save dialog to save file
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = sfi.Filter;
                if (!string.IsNullOrEmpty(sfi.InitialDirectory))
                {
                    sfd.InitialDirectory = sfi.InitialDirectory;
                }
                if ((bool)sfd.ShowDialog(parentWindow))
                {
                    sfi.WorkingFileSaveCallback(sfd.FileName);
                }
                else
                {
                    //user canceled out of save dialog. cancel the entire
                    //open operation
                    return false;
                }
            }
            else
            {
                //user wants to save first and there is a working file
                sfi.WorkingFileSaveCallback(sfi.currentWorkingFile);
            }
            return true;
        }
    }
}
